﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace PloobsEngine.Cameras
{
    public enum InterpolationType
    {
        BYTIME,BYSTEP
    }

    public enum TransitionMode
    {
        INTERPOLATED,IMEDIATELY
    }

    public enum State
    {
        INTERPOLATING,NORMAL
    }

    public struct CameraDescription
    {        
        public String name;
        public ICamera cam;
    };

    public class CameraManager
    {
        public static readonly String DEFAULTCAMERA  = "defaultCamera";
        public static readonly String INTERPOLATORCAMERA = "interpolatorCamera";        
        private List<CameraDescription> _cameras = new List<CameraDescription>();        
        private ICamera _activeCam;
        private int _activeCameraIndex;
        private State activeCameraType;
        
        public CameraManager()
        {            
            _activeCameraIndex = -1;            
        }

        /// <summary>
        /// Adiciona uma camera
        /// Se a camera tiver o nome DEFAULTCAMERA ela vira a camera atual tb
        /// </summary>
        /// <param name="cam"></param>
        /// <param name="name"></param>
        public void AddCamera(ICamera cam, String name)
        {
            CameraDescription cc;
            cc.cam = cam;
            cc.name = name;            
            _cameras.Add(cc);

            if (name == DEFAULTCAMERA)
            {
                _activeCam = cam;
            }
        }

        
        /// <summary>
        ///Adiciona uma camera e já a seta como a atual
        /// </summary>
        /// <param name="cam"></param>
        public void AddCamera(ICamera cam)
        {            
            AddCamera(cam, DEFAULTCAMERA);
            SetActiveCamera(DEFAULTCAMERA);         
        }

        /// <summary>
        /// Remove uma Camera
        /// Cuidado, pois ela pode estar Ativa !!!
        /// </summary>
        /// <param name="name">nome da camera</param>
        public void RemoveCamera(String name)
        {

            CameraDescription a = _cameras.Find(delegate(CameraDescription t) { return t.name == name; });

            if (a.cam == _activeCam)
            {                
                throw new Exception("cant remove actual camera");                
            }

            _cameras.Remove( a );
            
        }
        
        /// <summary>
        /// Retorna a Camera ativa
        /// </summary>
        public ICamera ActiveCamera
        {
            get
            {                
                return _activeCam;
            }
        }

        /// <summary>
        /// Seta uma camera ativa
        /// modo de transicao Imediata
        /// </summary>
        /// <param name="name"></param>
        public void SetActiveCamera(String name)
        {
            activeCameraType = State.NORMAL;
            _activeCameraIndex = _cameras.FindIndex(delegate(CameraDescription t) { return t.name == name; });
            _activeCam = _cameras[_activeCameraIndex].cam;            
        }
        /// <summary>
        /// Seta uma camera ativa
        /// modo de transicao Imediata
        /// </summary>
        /// <param name="name"></param>
        /// <param name="time">tempo de demora ou velocidade  -> para controlar o interpolador</param>
        public void SetActiveCamera(String name,  InterpolationType type ,float timeOrStep)
        {
            if (activeCameraType == State.NORMAL)
            {
                activeCameraType = State.INTERPOLATING;
                int ind = _cameras.FindIndex(delegate(CameraDescription t) { return t.name == name; });
                CameraInterpolator ci = new CameraInterpolator(_activeCam, _cameras[ind].cam, type, timeOrStep);               

                ci.OnInterpolationFinished += new CameraInterpolator.InterpolationFinished(ci_OnInterpolationFinished);
                ci.Name = INTERPOLATORCAMERA;
                CameraDescription cc = new CameraDescription();
                cc.cam = ci;
                cc.name = INTERPOLATORCAMERA;
                _cameras.Add(cc);
                int added = _cameras.FindIndex(delegate(CameraDescription t) { return t.name == INTERPOLATORCAMERA; });
                _activeCam = _cameras[added].cam;
            }
            else
            {
                CameraInterpolator ac = (_activeCam as CameraInterpolator);                
                int ind = _cameras.FindIndex(delegate(CameraDescription t) { return t.name == name; });
                ac.Reset(_activeCam, _cameras[ind].cam);                
            }
        }

        void ci_OnInterpolationFinished(ICamera start, ICamera end)
        {
            activeCameraType = State.NORMAL;
            SetActiveCamera(end.Name);
            RemoveCamera(INTERPOLATORCAMERA);
        }

        /// <summary>
        /// Retorna o nome da camera ativa
        /// </summary>
        /// <returns></returns>
        public String GetActiveCameraName()
        {
            return _cameras[_activeCameraIndex].name;
        }
        
        /// <summary>
        /// Retorna uma lista das cameras ativas
        /// </summary>
        /// <returns></returns>
        public List<CameraDescription> GetCamerasDescription()
        {
            return _cameras;
        }
        public State ActiveCameraType
        {
            get { return activeCameraType; }
        }

        public ICamera GetCamera(String name)
        {
            int camIndex = _cameras.FindIndex(delegate(CameraDescription t) { return t.name == name; });
            return _cameras[camIndex].cam;            
        }

    }
}
